package com.cms.intelligent_control.common.websocket

import android.os.Handler
import android.os.Looper
import android.util.Log
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import okhttp3.*
import okio.ByteString
import java.util.concurrent.TimeUnit

class WebSocketHelper(private val url: String) {
    companion object {
        const val TAG = "WebSocketHelper"
    }

    private val CONNECTED = 1
    private val CONNECTING = 0
    private val DISCONNECTED = -1

    private var disposable: Disposable? = null

    private val okHttpClient by lazy {
        OkHttpClient.Builder()
            .readTimeout(10, TimeUnit.SECONDS)//设置读取超时时间
            .writeTimeout(10, TimeUnit.SECONDS)//设置写的超时时间
            .connectTimeout(10, TimeUnit.SECONDS)//设置连接超时时间
            .build()
    }
    private val request by lazy {
        Request.Builder().url(url).build()
    }
    private val mainHandler by lazy {
        Handler(Looper.getMainLooper())
    }

    private var mWebSocket: WebSocket? = null
    private var mCurrentStatus = DISCONNECTED
    private var isOpen = false
    private var mCallback: SimpleCallback? = null


    fun start(callback: SimpleCallback.() -> Unit) {
        mCallback = SimpleCallback()
        mCallback?.callback()

        isOpen = true
        connect()
        disposable?.dispose()
        disposable = Observable.interval(60, TimeUnit.SECONDS)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({
                if (isOpen) {
                    val ping = mWebSocket?.send("ping")
                    Log.e(TAG, "ping result is $ping")
                    if (ping == null || !ping) {
                        mWebSocket?.close(1000, "正常关闭")
                        mCurrentStatus = DISCONNECTED
                        reconnect()
                    }
                } else {
                    disposable?.dispose()
                }
            }, {})
    }

    fun send(msg: String) {
        mWebSocket?.send(msg)
    }

    fun sendData(data: ByteArray) {
        mWebSocket?.send(ByteString.of(data, 0, data.size))
    }

    private fun connect() {
        if (mCurrentStatus == DISCONNECTED) {
            Log.e(TAG, "connecting")
            okHttpClient.dispatcher().cancelAll()
            mCurrentStatus = CONNECTING
            okHttpClient.newWebSocket(request, object : WebSocketListener() {
                override fun onOpen(webSocket: WebSocket, response: Response) {
                    super.onOpen(webSocket, response)
                    mWebSocket = webSocket
                    mCurrentStatus = CONNECTED
                    mainHandler.post { mCallback?.onOpen() }

                }

                override fun onMessage(webSocket: WebSocket, text: String) {
                    super.onMessage(webSocket, text)
                    mainHandler.post { mCallback?.onMessage(text) }

                }

                override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
                    super.onClosed(webSocket, code, reason)
                    Log.e(TAG, "onClosed:$code,$reason")
                    mCurrentStatus = DISCONNECTED
                    if (isOpen) {
                        reconnect()
                    }
                }

                override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
                    super.onFailure(webSocket, t, response)
                    Log.e(TAG, "onFailure:" + response?.toString(), t)
                    mCurrentStatus = DISCONNECTED
                    if (isOpen) {
                        reconnect()
                    }
                }
            })
        }
    }

    private fun reconnect() {
        val d = Observable.timer(1, TimeUnit.SECONDS)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({
                connect()
            }, {
                Log.e(TAG, "reconnect", it)
            })
    }


    fun close() {
        mWebSocket?.close(1000, "正常关闭")
        isOpen = false
    }
}
